package cn.zhaozhiqi.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.zhaozhiqi.mapper.ChargeRuleStartMapper;
import cn.zhaozhiqi.pojo.domain.ChargeRuleReturn;
import cn.zhaozhiqi.pojo.domain.ChargeRuleStart;
import cn.zhaozhiqi.remote.dto.ExpectsOrderDto;
import cn.zhaozhiqi.remote.dto.RuleComputedDto;
import cn.zhaozhiqi.service.IChargeRuleReturnService;
import cn.zhaozhiqi.service.IChargeRuleStartService;
import cn.zhaozhiqi.utils.AssertUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import java.math.BigDecimal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


/**
 * <p>
 * 计价规则-起步价 服务实现类
 * </p>
 *
 * @author zhaozhiqi
 * @since 2024-12-31
 */
@Service
public class ChargeRuleStartServiceImpl extends ServiceImpl<ChargeRuleStartMapper, ChargeRuleStart> implements IChargeRuleStartService {

    @Autowired
    private IChargeRuleReturnService chargeRuleReturnService;
    /**
     * 预估价格的方法：这个方法是order服务生成订单前调用，并且将相关字段保存在订单中
     * 1.拿到预计公里数、预计时间、下单时间以及订单号
     * 2.查询计价规则  当前时间里程价  返程费用等
     * 3.计算订单的预估总价
     * 预估总价 = 当前时间起步价 + 返程费用
     * 当前时间里程价 = 起步价 + 超出范围的里程 * 超出范围后的每公里价格
     * 返程费用 = 超出范围内的里程数 * 每公里返程费
     * @param dto 传入预估里程和下单时间
     * @return 返回预估价格以及相关计价规则
     */
    @Override
    public ExpectsOrderDto orderComputed(RuleComputedDto dto) {
        //首先根据下单时间拿到里程规则
        int hour = DateUtil.hour(dto.getCreateTime(), true);
        ChargeRuleStart rule = super.getOne(new LambdaQueryWrapper<ChargeRuleStart>()
                .ge(ChargeRuleStart::getHourEnd, hour)
                .le(ChargeRuleStart::getHourStart, hour));
        //断言如果rule存在，则进行下一步
        AssertUtil.isNotNull(rule,"里程规则拿取有误！");
        ExpectsOrderDto expectsOrderDto = new ExpectsOrderDto();
        //1.预估里程总价。有一种可能即乘客不超过起步里程，即不需要付额外里程和额外返程的费用。
        BigDecimal expectsMileage = dto.getExpectsMileage();//前端传来的预估里程
        //首先声明一个基础的里程总价，我们通过判断来进行增加价格
         BigDecimal expectsOrderAmount = rule.getAmount();//预估总价
        expectsOrderDto.setBaseMileageAmount(expectsOrderAmount);//设置基础里程价格
        BigDecimal baseMileage = rule.getBaseMileage();//起步价基础里程（公里）
        expectsOrderDto.setBaseMileage(baseMileage);
        BigDecimal exceedEveryKmAmount = rule.getExceedEveryKmAmount();//超出基础里程每公里价格
        expectsOrderDto.setExceedBaseMileageEveryKmAmount(exceedEveryKmAmount);
        if (expectsMileage.compareTo(baseMileage)>0){
            BigDecimal exceedBaseMileage = dto.getExpectsMileage().subtract(baseMileage);//超出起步价里程多少公里
            expectsOrderDto.setExceedBaseMileage(exceedBaseMileage);
            BigDecimal exceedBaseMileageAmount =exceedBaseMileage.multiply(exceedEveryKmAmount); //超出基础里程的价格
            expectsOrderDto.setExceedBaseMileageAmount(exceedBaseMileageAmount);
            BigDecimal mileageAmount = rule.getAmount().add(exceedBaseMileageAmount);//里程费(基础+超出)
            expectsOrderDto.setMileageAmount(mileageAmount);
            expectsOrderAmount = expectsOrderAmount.add(exceedBaseMileageAmount);//预估总价
        }
        expectsOrderDto.setReturnMileage(expectsMileage);//返回里程
        //2.预估返程价格,首先拿到返程里程的计价规则
        ChargeRuleReturn ruleReturn = chargeRuleReturnService.getOne(null);
        BigDecimal freeBaseReturnMileage = ruleReturn.getFreeBaseReturnMileage();//返程费免费公里数
        expectsOrderDto.setFreeBaseReturnMileage(freeBaseReturnMileage);
        BigDecimal exceedBaseReturnEveryKmAmount = ruleReturn.getExceedEveryKmAmount();//超出免费返程公里数，每公里收取的费用
        expectsOrderDto.setExceedBaseReturnEveryKmAmount(exceedBaseReturnEveryKmAmount);
        if (expectsMileage.compareTo(freeBaseReturnMileage) > 0){
            BigDecimal exceedFreeBaseReturnMileage = expectsMileage.subtract(freeBaseReturnMileage);//超出免费返程部分的里程
            expectsOrderDto.setExceedFreeBaseReturnMileage(exceedFreeBaseReturnMileage);
            BigDecimal returnAmont = exceedFreeBaseReturnMileage.multiply(exceedBaseReturnEveryKmAmount);//返程费(超出公里*每公里价格)
            expectsOrderDto.setReturnAmont(returnAmont);
            expectsOrderAmount = expectsOrderAmount.add(returnAmont);//预估总价
        }
        expectsOrderDto.setExpectsOrderAmount(expectsOrderAmount);//设置预估总价
        return expectsOrderDto;
    }
}
